package com.lee9213.core.aspect;

import java.lang.reflect.Method;

import javax.transaction.UserTransaction;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.lee9213.core.annotation.Transactional;
import com.lee9213.core.exception.TransactionException;
import com.lee9213.core.transaction.JtaTransactionManager;

/**
 * 事务处理AOP
 *
 * @author libo
 * @version 1.0
 * @date 2017/11/23 16:39
 */
@Component
@Aspect
@Order(0)
public class JtaTransactionAspect {
    private static final Logger LOGGER = LoggerFactory.getLogger(JtaTransactionAspect.class);
    @Autowired
    @Qualifier("jtaTransactionManager")
    private JtaTransactionManager transactionManager;

    @Pointcut("execution(* com.lee9213..*..dao.*.*(..))")
    private void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result = null;
        Class<?> targetClass = point.getTarget().getClass();
        Method targetMethod = ((MethodSignature) point.getSignature()).getMethod();
        Transactional classAnnotation = targetClass.getAnnotation(Transactional.class);
        Transactional methodAnnotation = targetMethod.getAnnotation(Transactional.class);

        if ((methodAnnotation == null && classAnnotation == null)
                || methodAnnotation != null && methodAnnotation.readOnly()
                || (classAnnotation != null && classAnnotation.readOnly())) {
            result = point.proceed();
        } else {
            UserTransaction userTransaction = null;
            try {
                userTransaction = transactionManager.getUserTransaction();
                if (userTransaction.getStatus() != 6) {
                    throw new TransactionException("不支持事务嵌套");
                }
                LOGGER.debug("Atomikos Transaction start");
                userTransaction.begin();
                result = point.proceed();
                userTransaction.commit();
                LOGGER.debug("Atomikos Transaction commit");
            } catch (Throwable throwable) {
                if (throwable instanceof TransactionException) {
                    throw new TransactionException("不支持事务嵌套");
                }
                if (userTransaction != null) {
                    userTransaction.rollback();
                    LOGGER.debug("Atomikos Transaction rollback");
                }
                throw throwable;

            }
        }
        return result;
    }

}
